﻿#ifndef MUYURP_LIT_INCLUDED
#define MUYURP_LIT_INCLUDED

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl"

#define MAX_VISIBLE_LIGHTS 16
CBUFFER_START(_LightBuffer)
float4 _VisibleLightColors[MAX_VISIBLE_LIGHTS];
float4 _VisibleLightDirectionsOrPositions[MAX_VISIBLE_LIGHTS];
float4 _VisibleLightAttenuations[MAX_VISIBLE_LIGHTS];
float4 _VisibleSpotLightDirection[MAX_VISIBLE_LIGHTS];
CBUFFER_END

CBUFFER_START(UnityPerFrame)
float4x4 unity_MatrixVP;
CBUFFER_END

CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;
float4 unity_LightIndicesOffsetAndCount;
float4 unity_4LightIndices0,unity_4LightIndices1;
CBUFFER_END

#define UNITY_MATRIX_M unity_ObjectToWorld
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"

//CBUFFER_START(UnityPerMaterial)
//float4 _Color;
//CBUFFER_END
UNITY_INSTANCING_BUFFER_START(PerInstance)
UNITY_DEFINE_INSTANCED_PROP(float4,_Color)
UNITY_INSTANCING_BUFFER_END(PerInstance)

CBUFFER_START(_ShadowBuffer)
float4x4 _WorldToShadowMatrix;
float _ShadowStrength;
CBUFFER_END

TEXTURE2D_SHADOW(_ShadowMap);
SAMPLER_CMP(sampler_ShadowMap);

struct VertexInput{
	float4 pos:POSITION0;
	float3 normal:NORMAL0;
	UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct VertexOutput{
	float4 clipPos:SV_POSITION;
	float3 normal:NORMAL0;
	float3 worldPos:TEXCOORD0;
	float3 vertexLighting:TEXCOORD1;
	UNITY_VERTEX_INPUT_INSTANCE_ID
};

float ShadowAttenuation (float3 worldPos) {
	float4 shadowPos = mul(_WorldToShadowMatrix, float4(worldPos, 1.0));
	shadowPos.xyz /= shadowPos.w;
	float attenuation = SAMPLE_TEXTURE2D_SHADOW(_ShadowMap, sampler_ShadowMap, shadowPos.xyz);
	return lerp(1,attenuation,_ShadowStrength);
}

float3 DiffuseColor(int index,float3 normal,float3 worldPos,float shadowAttenuation){
	float3 lightColor = _VisibleLightColors[index].xyz;
	float4 lightPositionOrDirection = _VisibleLightDirectionsOrPositions[index];
	float3 lightVector = lightPositionOrDirection.xyz - worldPos * lightPositionOrDirection.w;
	float3 lightDirection = normalize(lightVector);
	float3 spotDirection = _VisibleSpotLightDirection[index].xyz;
	float4 lightAttenuation = _VisibleLightAttenuations[index];
	float diffuseRate = saturate(dot(normal, lightDirection));

	float rangeFade = dot(lightVector,lightVector) * lightAttenuation.x;
	rangeFade = saturate(1.0 - rangeFade*rangeFade);
	rangeFade *= rangeFade;

	float spotFade = dot(spotDirection, lightDirection);
	spotFade = saturate(spotFade * lightAttenuation.z + lightAttenuation.w);
	spotFade *= spotFade;

	float distanceSqr = max(dot(lightVector, lightVector), 0.00001);
	diffuseRate *= shadowAttenuation * spotFade * rangeFade / distanceSqr;
	return diffuseRate * lightColor;
}

VertexOutput LitPassVertex(VertexInput input)
{
	VertexOutput o = (VertexOutput)0;
	UNITY_SETUP_INSTANCE_ID(input);
	UNITY_TRANSFER_INSTANCE_ID(input,o);
	o.worldPos = mul(UNITY_MATRIX_M,float4(input.pos.xyz,1.0)).xyz;
	o.clipPos = mul(unity_MatrixVP,float4(o.worldPos,1.0));
	o.normal = mul((float3x3)UNITY_MATRIX_M,input.normal);
	o.vertexLighting = 0;
	for(int i = 4;i < min(unity_LightIndicesOffsetAndCount.y,8);i++)
	{
		int lightIndex = unity_4LightIndices1[i - 4];
		o.vertexLighting += 
			DiffuseColor(lightIndex,o.normal,o.worldPos,1.0);
	}
	return o;
}

float4 LitPassFragment(VertexOutput input):SV_TARGET0{
	UNITY_SETUP_INSTANCE_ID(input);
	input.normal = normalize(input.normal);
	float3 albedo = UNITY_ACCESS_INSTANCED_PROP(PerInstance,_Color).rgb;
	float3 diffuseLight = input.vertexLighting;
	float shadowAttenuation = ShadowAttenuation(input.worldPos);
	for(int i = 0;i < min(unity_LightIndicesOffsetAndCount.y,4);i++)
	{
		int lightIndex = unity_4LightIndices0[i];
		diffuseLight += 
			DiffuseColor(lightIndex,normalize(input.normal),input.worldPos,shadowAttenuation);
	}
	float3 finalColor = diffuseLight * _Color;
	return float4(finalColor,1.0);
}

#endif //MUYURP_LIT_INCLUDED